/********************************************
*
*
*
********************************************/

#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */

#include "d_task.h"
#include "d_lock.h"
#include "d_list.h"
#include "d_mem.h"
#include "d_tick.h"
#include "d_cfg.h"

typedef struct tagSysTickCtl {
    UINT32        ulSysTick;
    UINT32        ulMilliSec;
    LockHandle    stLock;
    TASK_HANDLE   tickTask;
    DMS_SYS_HOOK  pfnTimerHook;
    DMS_LIST_NODE stHookListHead;
}SYS_TICK_INFO;


typedef struct tagHookNode {
    DMS_LIST_NODE stListNode;
    DMS_SYS_HOOK  pfnHook;
}TICK_HOOK_S;


SYS_TICK_INFO m_stSysTickInfo;

#define TICK_LOCK     DMS_MutexLock(m_stSysTickInfo.stLock)
#define TICK_ULOCK    DMS_MutexUnLock(m_stSysTickInfo.stLock)

VOID DmsTickTimerHook(UINT32 ulSysTick)
{

}

VOID DmsTickTaskFunc(UINT32 ulMilliSec,VOID * pParam)
{
    UINT32 ulSysTick = m_stSysTickInfo.ulSysTick;
    DMS_LIST_NODE * pstNode;
    DMS_LIST_NODE * pstHead = &(m_stSysTickInfo.stHookListHead);
    TICK_HOOK_S   * pstTick;

    if( 0 == ulMilliSec )
    {
        return;
    }

    for(;;)
    {
        DMS_TaskDelay(ulMilliSec);

        ulSysTick++;
        m_stSysTickInfo.ulSysTick = ulSysTick;
        m_stSysTickInfo.pfnTimerHook(ulSysTick);

        TICK_LOCK;
        DMS_LIST_TRAVERSAL(pstNode, pstHead)
        {
            pstTick = DMS_LIST_OFFSET(pstNode, TICK_HOOK_S, stListNode);
            pstTick->pfnHook(ulSysTick);
        }
        TICK_ULOCK;
    }
}


UINT32 DMS_TickInit(char * keys)
{
    UINT32 ulTaskMode;
    UINT32 UlTaskPrio;
    UINT32 ulRet;

    ulTaskMode = DMS_CfgUintValueGet(keys, "DMS_TICK_SCH_MODE", DMS_TASK_SCH_FIFO);
    UlTaskPrio = DMS_CfgUintValueGet(keys, "DMS_TICK_PRIO", DMS_TASK_PRIORITY_9);

    ulRet = DMS_MutexCreate(&m_stSysTickInfo.stLock);
    if(DMS_OK != ulRet)
    {
        return ulRet;
    }

    DMS_LIST_INIT(&m_stSysTickInfo.stHookListHead);
    m_stSysTickInfo.pfnTimerHook = DmsTickTimerHook;
    m_stSysTickInfo.ulSysTick    = 0;
    m_stSysTickInfo.ulMilliSec   = 10;

    ulRet = DMS_TaskCreateEx(&m_stSysTickInfo.tickTask,
                             "_TICK",
                             ulTaskMode,
                             UlTaskPrio,
                             DmsTickTaskFunc,
                             m_stSysTickInfo.ulMilliSec,
                             NULL);
    if(DMS_OK != ulRet)
    {
        (VOID)DMS_MutexDelete(m_stSysTickInfo.stLock);
        return ulRet;
    }

    return DMS_OK;
}

UINT32 DMS_TickFini()
{
    return DMS_OK;
}

UINT32 DMS_RegTimerHook(DMS_SYS_HOOK pfnHook)
{
    if(NULL == pfnHook)
    {
        return DMS_INVALID_PARAM;
    }
    m_stSysTickInfo.pfnTimerHook = pfnHook;
    return DMS_OK;
}

UINT32 DMS_RegTickHook(DMS_SYS_HOOK pfnHook)
{
    TICK_HOOK_S * pstTick;
    DMS_LIST_NODE * pstNode;
    DMS_LIST_NODE * pstHead = &m_stSysTickInfo.stHookListHead;

    TICK_LOCK;
    DMS_LIST_TRAVERSAL(pstNode, pstHead)
    {
        pstTick = DMS_LIST_OFFSET(pstNode, TICK_HOOK_S, stListNode);
        if(pstTick->pfnHook == pfnHook)
        {
            TICK_ULOCK;
            return DMS_ERR_TICK_SAME_HOOK;
        }
    }

    pstTick = (TICK_HOOK_S *)DMS_MemAlloc(sizeof(TICK_HOOK_S));
    if(NULL == pstTick)
    {
        TICK_ULOCK;
        return DMS_NOSYS_MEM;
    }

    pstTick->pfnHook = pfnHook;
    DMS_LIST_ADD(&(pstTick->stListNode), pstHead);

    TICK_ULOCK;
    return DMS_OK;
}

UINT32 DMS_UnRegTickHook(DMS_SYS_HOOK pfnHook)
{
    TICK_HOOK_S * pstTick;
    DMS_LIST_NODE * pstNode;
    DMS_LIST_NODE * pstHead = &m_stSysTickInfo.stHookListHead;

    TICK_LOCK;
    DMS_LIST_TRAVERSAL(pstNode, pstHead)
    {
        pstTick = DMS_LIST_OFFSET(pstNode, TICK_HOOK_S, stListNode);
        if(pstTick->pfnHook == pfnHook)
        {
            DMS_LIST_REMOVE(&pstTick->stListNode);
            TICK_ULOCK;
            DMS_MemFree((VOID *)pstTick);
            return DMS_OK;
        }
    }

    TICK_ULOCK;
    return DMS_ERR_TICK_NOFIND_HOOK;
}

UINT32 DMS_GetSysTick(VOID)
{
    return m_stSysTickInfo.ulSysTick;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

